import classNames from 'classnames';
import { isValidElement, ReactNode, useEffect, useRef, useState } from 'react';
import SelectContext from 'src/context/SelectContext';
import IcArrowDown from 'src/image/ic-arrow-down.svg';
import Popover from '../Popover';
import style from './Select.module.scss';

/**
 * usage example:
 *
 * <Select>
 *   <SelectOption value="aa">a</SelectOption>
 *   <SelectOption value="bb">b</SelectOption>
 *   <SelectOption value="cc">c</SelectOption>
 * </Select>
 */

export type Props = {
  children: ReactNode | ReactNode[];
  className?: string;
  defaultValue?: string;
  value?: string;
  onChange?: (v: string) => void;
  label?: string;
  hint?: string;
  error?: any;
  asterisked?: boolean;
};

const Select = ({
  children,
  className,
  defaultValue,
  value: controlledSelectedValue,
  onChange,
  label,
  hint,
  error,
  asterisked = false,
}: Props) => {
  const [open, setOpen] = useState<boolean>(false);
  const [options, setOptions] = useState<{ value: string; children: ReactNode }[]>([]);
  const [selected, setSelected] = useState<string>(defaultValue ?? '');
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    setOptions(
      (Array.isArray(children) ? children : [children]).map((child) =>
        isValidElement(child) ? child.props : null,
      ),
    );
  }, []);

  const handleChange = (v: string) => {
    setOpen(false);
    if (controlledSelectedValue === undefined) setSelected(v);

    onChange && onChange(v);
  };

  return (
    <SelectContext.Provider value={{ current: controlledSelectedValue ?? selected, handleChange }}>
      <div>
        {label && (
          <div className={classNames(style.label)}>
            {label}
            {asterisked && <span className={style.asterisk}>*</span>}
          </div>
        )}
        <div
          className={classNames(style.select, className, { [style.error]: !!error })}
          onClick={() => setOpen(!open)}
          ref={ref}
        >
          <div>
            {options.find((v) => v.value === (controlledSelectedValue ?? selected))?.children}
          </div>
          <img src={IcArrowDown} />
        </div>
        {typeof error === 'string' && <div className={style.errorMessage}>{error}</div>}
        {hint && <div className={style.hint}>{hint}</div>}
      </div>
      <Popover
        open={open}
        onClose={() => setOpen(false)}
        anchorEl={ref.current}
        cssProperties={{ width: ref.current?.offsetWidth }}
      >
        {children}
      </Popover>
    </SelectContext.Provider>
  );
};

export default Select;
